#include "../include/MySQLClient.h"
#include "../include/Logger.h"

using std::cout;
using std::endl;
namespace myNameSpace {
MySQLClient::MySQLClient() {
    init();
}

MySQLClient::~MySQLClient() {
    mysql_close(&_mysqlConnection);
}

bool MySQLClient::connect(const string &host, const string &user, const string &password, const string &database, unsigned short port) {
    MYSQL *pMysqlConnection = mysql_real_connect(&_mysqlConnection, host.c_str(), user.c_str(), password.c_str(), database.c_str(), port, nullptr, 0);
    if (!pMysqlConnection) {
        moqi::LOG_ERROR("(%d, %s.)", mysql_errno(&_mysqlConnection), mysql_error(&_mysqlConnection));
        return false;
    }
    return true;
}

bool MySQLClient::writeOperationQuery(const string &sql) {
    int ret = mysql_real_query(&_mysqlConnection, sql.c_str(), sql.size());
    if (ret) {
        moqi::LOG_ERROR("(%d, %s.)", mysql_errno(&_mysqlConnection), mysql_error(&_mysqlConnection));
        return false;
    }
    moqi::LOG_INFO("Query OK, %d rows affected.", mysql_affected_rows(&_mysqlConnection));
    return true;
}

vector<vector<string>> MySQLClient::readOperationQuery(const string &sql) {
    int ret = mysql_real_query(&_mysqlConnection, sql.c_str(), sql.size());
    if (ret) {
        moqi::LOG_ERROR("(%d, %s.)", mysql_errno(&_mysqlConnection), mysql_error(&_mysqlConnection));
        /* mysql_close(&_mysqlConnection); */
        return vector<vector<string>>();
    }
    MYSQL_RES *pResult = mysql_use_result(&_mysqlConnection);
    if (!pResult) {
        moqi::LOG_ERROR("(%d, %s.)", mysql_errno(&_mysqlConnection), mysql_error(&_mysqlConnection));
        /* mysql_close(&_mysqlConnection); */
        return vector<vector<string>>();
    }
    unsigned int cols = mysql_num_fields(pResult);
    vector<vector<string>> result;
    unsigned int rows = 0;
    while (MYSQL_ROW mysqlRow = mysql_fetch_row(pResult)) {
        vector<string> row;
        row.reserve(cols);
        for (unsigned int i = 0; i < cols; ++i) {
            row.emplace_back(mysqlRow[i]);
        }
        result.emplace_back(row);
        ++rows;
    }
    moqi::LOG_INFO("%u row(s) in set.", rows);
    return result;
}

bool MySQLClient::isExist(const string &tableName, const string &keyField, const string &key) {
    char sql[512];
    sprintf(sql, "SELECT 1 from %s WHERE %s = '%s' LIMIT 1;", tableName.c_str(), keyField.c_str(), key.c_str());
    vector<vector<string>> result = readOperationQuery(sql);
    return !result.empty();
}

// 给表table中NameField_key=key的一行中，Field_data列添加数据data
/* bool MySQLClient::appendData(const string &tableName, const string &dataField, const string &data, const string &keyField, const string &key) */
/* { */
/*     char buffer[512]; // 确保缓冲区足够大！ */
  
/*     sprintf(buffer, "UPDATE %s SET %s=%s WHERE %s = %s;", tableName.c_str(), */
/*             dataField.c_str(), data.c_str(), keyField.c_str(), key.c_str()); */
/*     return writeOperationQuery(string(buffer)); */
/* } */

// 从tableName表中查找dataField的值，条件为keyField=key，若存在则返回dataField对应的字段值，若不存在则返回空字符串
string MySQLClient::findData(const string &tableName, const string &dataField, const string &keyField, const string &key) {
    char buffer[512] = {0}; // 确保缓冲区足够大！
    sprintf(buffer, "SELECT %s FROM %s WHERE %s = '%s';", dataField.c_str(), tableName.c_str(), keyField.c_str(), key.c_str());
    vector<vector<string>> result = readOperationQuery(buffer);
    if (!result.empty()) {
        return result[0][0];
    }
    else {
        return string();
    }
}
 
/* void MySQLClient::dump(const vector<vector<string>> &res) */
/* { */
/*     cout << "result set has " << res.size() << " row(s)" << endl; */
/*     for (auto &vec : res) */
/*     { */
/*         for (auto &Field : vec) */
/*         { */
/*             cout << Field << "\t"; */
/*         } */
/*         cout << endl; */
/*     } */
/*     cout << endl; */
/* } */

void MySQLClient::init() {
    MYSQL *pMysqlConnection = mysql_init(&_mysqlConnection);
    if (!pMysqlConnection) {
        moqi::LOG_ERROR("mysql_init failed.");
        exit(EXIT_FAILURE);
    }
}
} // end of namespace myNameSpace
